#ifndef FAVORITE_H_
#define FAVORITE_H_

#include <gtkmm.h>
#include <boost/shared_ptr.hpp>
#include <list>

#include "conf/collection.h"
#include "conf/attribute.h"
#include "misc.h"
#include "shellwords.h"

namespace gpyp {

class Channel;

class Favorite;

class Rule : public conf::Element {
  friend class conf::Collection<Rule, Favorite>;
public:
  enum Target {
    TARGET_NONE     = 0,
    TARGET_NAME     = 1 << 0,
    TARGET_GENRE    = 1 << 1,
    TARGET_DESC     = 1 << 2,
    TARGET_COMMENT  = 1 << 3,
    TARGET_TRACK    = 1 << 4,
    TARGET_CONTACT  = 1 << 5,
    TARGET_YPNAME   = 1 << 6,
    TARGET_TYPE     = 1 << 7,
    TARGET_ID       = 1 << 8,
    TARGET_TIP      = 1 << 9,
  };

protected:
  conf::RefAttributeStr  word_;
  conf::RefAttributeBool case_sensitive_;
  conf::RefAttributeBool invert_;
  conf::RefAttributeBool target_name_;
  conf::RefAttributeBool target_genre_;
  conf::RefAttributeBool target_desc_;
  conf::RefAttributeBool target_comment_;
  conf::RefAttributeBool target_track_;
  conf::RefAttributeBool target_contact_;
  conf::RefAttributeBool target_ypname_;
  conf::RefAttributeBool target_type_;
  conf::RefAttributeBool target_id_;
  conf::RefAttributeBool target_tip_;

  RefRegex re_;
  bool     re_valid_;

  void update_re();

public:
  inline conf::RefAttributeStr  word() {
    return word_;
  }
  inline conf::RefAttributeBool case_sensitive() {
    return case_sensitive_;
  }
  inline conf::RefAttributeBool invert() {
    return invert_;
  }
  inline conf::RefAttributeBool target_name() {
    return target_name_;
  }
  inline conf::RefAttributeBool target_genre() {
    return target_genre_;
  }
  inline conf::RefAttributeBool target_desc() {
    return target_desc_;
  }
  inline conf::RefAttributeBool target_comment() {
    return target_comment_;
  }
  inline conf::RefAttributeBool target_track() {
    return target_track_;
  }
  inline conf::RefAttributeBool target_contact() {
    return target_contact_;
  }
  inline conf::RefAttributeBool target_ypname() {
    return target_ypname_;
  }
  inline conf::RefAttributeBool target_type() {
    return target_type_;
  }
  inline conf::RefAttributeBool target_id() {
    return target_id_;
  }
  inline conf::RefAttributeBool target_tip() {
    return target_tip_;
  }

  inline RefRegex get_re() {
    return re_;
  }
  inline bool is_word_valid() const {
    return re_valid_;
  }

  void set_target(Target target);

  bool match(Channel &ch);

  Rule(const Glib::ustring &name);
};
typedef boost::shared_ptr<Rule> RefRule;

ENUM_FLAG_OPERATORS(Rule::Target);

class FavoriteCollection;

enum ChSort {
  CHSORT_NONE = 0,
  CHSORT_TOP,
  CHSORT_MIDDLE,
  CHSORT_BOTTOM,
  CHSORT_INVALID
};
class AttributeChSort : public conf::AttributeEnum<ChSort, AttributeChSort> {
  friend class conf::AttributeEnum<ChSort, AttributeChSort>;
protected:
  static NameTable _name_table[];

public:
  inline AttributeChSort(const Glib::ustring &name, ChSort defval) :
    conf::AttributeEnum<ChSort, AttributeChSort>(name, defval)
  {
  }
};
typedef conf::RefAttributeEnum<AttributeChSort> RefAttributeChSort;

class Favorite : public conf::Collection<Rule, Favorite> {
  friend class conf::Collection<Favorite, FavoriteCollection>;
private:
  conf::RefAttributeStr     name_;
  conf::RefAttributeBool    enable_;
  conf::RefAttributeBool    filter_;
  conf::RefAttributeBool    rule_or_;
  conf::RefAttributeInt     rule_age_min_;
  conf::RefAttributeInt     rule_age_max_;

  RefAttributeColor         bgcolor_;
  RefAttributeColor         fgcolor_;
  conf::RefAttributeStr     font_;
  RefAttributeChSort        sort_;
  conf::RefAttributeTribool ng_;
  conf::RefAttributeTribool auto_play_;
  conf::RefAttributeTribool auto_record_;
  conf::RefAttributeTribool notify_new_;
  conf::RefAttributeTribool notify_change_;
  conf::RefAttributeStr     notify_sound_;
  conf::RefAttributeDouble  notify_sound_volume_;

protected:
  RefRule on_create_item(const Glib::ustring &name);

public:
  inline conf::RefAttributeStr name() {
    return name_;
  }
  inline conf::RefAttributeBool enable() {
    return enable_;
  }
  inline conf::RefAttributeBool filter() {
    return filter_;
  }
  inline conf::RefAttributeBool rule_or() {
    return rule_or_;
  }
  inline conf::RefAttributeInt rule_age_min() {
    return rule_age_min_;
  }
  inline conf::RefAttributeInt rule_age_max() {
    return rule_age_max_;
  }

  inline RefAttributeColor bgcolor() {
    return bgcolor_;
  }
  inline RefAttributeColor fgcolor() {
    return fgcolor_;
  }
  inline conf::RefAttributeStr font() {
    return font_;
  }
  inline RefAttributeChSort sort() {
    return sort_;
  }
  inline conf::RefAttributeTribool ng() {
    return ng_;
  }
  inline conf::RefAttributeTribool auto_play() {
    return auto_play_;
  }
  inline conf::RefAttributeTribool auto_record() {
    return auto_record_;
  }
  inline conf::RefAttributeTribool notify_new() {
    return notify_new_;
  }
  inline conf::RefAttributeTribool notify_change() {
    return notify_change_;
  }
  inline conf::RefAttributeStr notify_sound() {
    return notify_sound_;
  }
  inline conf::RefAttributeDouble notify_sound_volume() {
    return notify_sound_volume_;
  }

  RefRule add_item();
  RefRule add_item(const Glib::ustring &word,
                   Rule::Target target,
                   bool case_sensitive = false,
                   bool invert = false);
  RefRule add_item(Rule::Target target);

  bool match(Channel &ch);

  Favorite(const Glib::ustring &name);
};
typedef boost::shared_ptr<Favorite> RefFavorite;

class BuiltinCommand;
struct CommandOpts;
class FavoriteCollection :
    public conf::Collection<Favorite, FavoriteCollection> {
public:
  static const char *PRESET_BANDWIDTH;

  static const char *PRESET_YPINFO_GENERAL;
  static const char *PRESET_YPINFO_INDEX_TXT;
  static const char *PRESET_YPINFO_MISC;

private:
  Application    &app_;
  BuiltinCommand &bc_favorite_;
  BuiltinCommand &bc_rule_;

protected:
  RefFavorite on_create_item(const Glib::ustring &name);
  virtual void on_load_default();

public:
  RefFavorite add_item();
  RefFavorite add_item(const Glib::ustring &name,
                       bool                 enable  = true,
                       bool                 filter  = false,
                       const Color         &bgcolor = Color(),
                       const Color         &fgcolor = Color(),
                       ChSort               sort    = CHSORT_NONE);

  RefFavorite find(const Glib::ustring &name);
  RefFavorite find(RefRegex re);

private:
  bool bc_rule_append_word(ShellLine &line, CommandOpts &opts);

public:
  FavoriteCollection(Application &app);
};
typedef boost::shared_ptr<FavoriteCollection> RefFavoriteCollection;

class FavoriteMatch {
public:
  typedef std::list<RefFavorite> MatchedList;
  typedef MatchedList::iterator iterator;

private:
  Color         bgcolor_;
  Color         fgcolor_;
  Glib::ustring font_;
  ChSort        sort_;
  bool          ng_;
  bool          auto_play_;
  bool          auto_record_;
  bool          notify_new_;
  bool          notify_change_;
  Glib::ustring notify_sound_;
  double        notify_sound_volume_;
  int           notify_sound_rank_;

  MatchedList   matched_;

public:
  inline const Color &bgcolor() const {
    return bgcolor_;
  }
  inline const Color &fgcolor() const {
    return fgcolor_;
  }
  inline const Glib::ustring &font() const {
    return font_;
  }
  inline ChSort sort() const {
    return sort_;
  }
  inline bool ng() const {
    return ng_;
  }
  inline bool auto_play() const {
    return auto_play_;
  }
  inline bool auto_record() const {
    return auto_record_;
  }
  inline bool notify_new() const {
    return notify_new_;
  }
  inline bool notify_change() const {
    return notify_change_;
  }
  inline const Glib::ustring &notify_sound() const {
    return notify_sound_;
  }
  inline double notify_sound_volume() const {
    return notify_sound_volume_;
  }
  inline int notify_sound_rank() const {
    return notify_sound_rank_;
  }

  inline iterator begin() {
    return matched_.begin();
  }
  inline iterator end() {
    return matched_.end();
  }

  FavoriteMatch(RefFavoriteCollection favorites, Channel &ch);
};
typedef boost::shared_ptr<FavoriteMatch> RefFavoriteMatch;

}/*gpyp*/

#endif/*FAVORITE_H_*/
